package com.xbongbong.pro.rabbitmq.config;

import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.http.client.reactive.ReactorResourceFactory;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;
import reactor.netty.resources.ConnectionProvider;
import reactor.netty.resources.LoopResources;

import java.time.Duration;
import java.util.function.Function;

import static io.netty.channel.ChannelOption.CONNECT_TIMEOUT_MILLIS;
import static io.netty.channel.ChannelOption.TCP_NODELAY;

/**
 * WebClient Netty连接池配置
 * 配置参数见{@link WebHookConstant}
 * @author 李少杰
 * @version v1.0.0
 * @date 2021/9/15 15:58
 */
@Configuration
public class WebClientConfig {

    @Bean
    ReactorResourceFactory resourceFactory() {
        ReactorResourceFactory factory = new ReactorResourceFactory();
        //不使用spring全局资源
        factory.setUseGlobalResources(false);
        //使用自定义连接池
        factory.setConnectionProvider(
                ConnectionProvider.builder(WebHookConstant.CONNECTION_NAME)
                        .maxConnections(WebHookConstant.MAX_CONNECTION)
                        // keep the backwards compatibility
                        .pendingAcquireMaxCount(-1)
                        .pendingAcquireTimeout(Duration.ofMillis(WebHookConstant.CONNECTION_REQUEST_TIMEOUT))
                        .maxIdleTime(Duration.ofMillis(WebHookConstant.MAX_IDLE_TIMEOUT))
                        .maxLifeTime(Duration.ofMillis(WebHookConstant.MAX_LIFE_TIMEOUT))
                        .build()
        );
        factory.setLoopResources(LoopResources.create(WebHookConstant.CONNECTION_NAME, WebHookConstant.DEFAULT_MAX_PRE_ROUTE, true));
        return factory;
    }

    @Bean
    WebClient webClient() {
        Function<HttpClient, HttpClient> mapper = client ->
                client.tcpConfiguration(c ->
                        c.option(CONNECT_TIMEOUT_MILLIS, WebHookConstant.CONNECT_TIMEOUT)
                                .option(TCP_NODELAY, true)
                                .doOnConnected(conn -> {
                                    conn.addHandlerLast(new ReadTimeoutHandler(WebHookConstant.SOCKET_TIMEOUT));
                                    conn.addHandlerLast(new WriteTimeoutHandler(WebHookConstant.SOCKET_TIMEOUT));
                                }));

        ClientHttpConnector connector =
                new ReactorClientHttpConnector(resourceFactory(), mapper);
        return WebClient.builder().clientConnector(connector).build();
    }
}
